﻿using Autofac;
using duia.Canteenpay.Application.AppService;
using duia.Canteenpay.Application.Querys;
using duia.Canteenpay.Domain.IRepository;
using duia.Canteenpay.Infrastructure.Domain;
using duia.Canteenpay.Repository;
using duia.Canteenpay.Repository.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.OpenApi.Models;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace duia.Canteenpay.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            //注册过滤器
            services.AddControllers(optiopn =>
            {
                //注册全局异常过滤器
                optiopn.Filters.Add(typeof(AppExceptionFilter));
                optiopn.Filters.Add(typeof(AppResultFilter));

            })
            //使用NewtonsoftJson序列化数据
            .AddNewtonsoftJson(options =>
            {
                //取消骆驼命名法
                //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                //设置返回datetime时间格式
                options.SerializerSettings.DateFormatString = "yyyy'/'MM'/'dd' 'HH':'mm':'ss";
            });
            //注册MemoryCache缓存中间件
            services.AddMemoryCache();
            //注册Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "通用餐厅饭卡管理系统", Version = "v1" });
                // 解决相同类名会报错的问题
                c.CustomSchemaIds(type => type.FullName);
                //解决其他类库的属性注释不显示问题
                foreach (var item in XmlCommentsFilePath)
                {
                    c.IncludeXmlComments(item); //Locate the XML file being generated by ASP.NET...
                }

                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "请输入token",
                    Name = "token",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "",
                    Scheme = ""
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
                c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
            });
            //注册EF-DbContext
            services.AddAppContext(Configuration);
            //services.AddScoped<IAppUnitOfWork, AppUnitOfWork>();
            //services.AddScoped<IUserRepository, UserRepository>();
            //services.AddScoped<IDishesCategoryRepository, DishesCategoryRepository>();
            //services.AddScoped<UsersAppService>();

        }

        public void ConfigureContainer(ContainerBuilder builder)
        {

            //程序集
            //Type baseType = typeof(IDependency);
            //IEnumerable<Assembly> allAssemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(Assembly.Load);
            //Assembly[] assemblies = allAssemblies.ToArray();
            //builder.RegisterAssemblyTypes(assemblies).Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract).AsImplementedInterfaces().InstancePerLifetimeScope(); //保证对象生命周期基于请求
            ////PropertiesAutowired即可使用属性注入
            //builder.RegisterAssemblyTypes(typeof(BaseAppService).Assembly).InstancePerLifetimeScope().PropertiesAutowired();

            ////使用第三方IOC需要继承接口重新注入
            //builder.RegisterType<AppUnitOfWork>().As<IQueryableUnitOfWork>().InstancePerLifetimeScope();
            ////单例注入EF实体映射，本项目使用同一Dbcontext，可不用此方法实现
            //builder.RegisterType<OnModelCreating>().As<IOnModelCreating>().SingleInstance();

            //builder.RegisterType<AppUnitOfWork>().As<IAppUnitOfWork>().InstancePerLifetimeScope();
            builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
            builder.RegisterType<DishesCategoryRepository>().As<IDishesCategoryRepository>().InstancePerLifetimeScope();
            builder.RegisterType<UsersAppService>().InstancePerLifetimeScope();
            builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().InstancePerLifetimeScope();
            var readSql = Configuration["SqlConnection:ReadMySql"].ToString();
            builder.Register(c => new UserQuerys(readSql));

            //在控制器中使用属性依赖注入，其中注入属性必须标注为public
            // var controllerBaseType = typeof(BaseApiController);
            //builder.RegisterAssemblyTypes(typeof(Program).Assembly).Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType).PropertiesAutowired();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            AutofacBuilder.InitContainer(app.ApplicationServices);

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "duia.Canteenpay.WebApi v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();
            //全局异常中间件
            app.UseMiddleware(typeof(ExceptionMiddleware));

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });


        }

        /// <summary>
        /// 扫描所引用的程序的生成的XML文件
        /// </summary>
        static List<string> XmlCommentsFilePath
        {
            get
            {
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                DirectoryInfo d = new DirectoryInfo(basePath);
                FileInfo[] files = d.GetFiles("*.xml");
                var xmls = files.Select(a => Path.Combine(basePath, a.FullName)).ToList();
                return xmls;
            }
        }
    }

    /// <summary>
    /// 服务扩展
    /// </summary>
    static class ExtensionsMethods
    {
        public static IServiceCollection AddAppContext(this IServiceCollection services, IConfiguration configuration)
        {
            //注册EF-DbContext
            services.AddDbContextPool<AppUnitOfWork>(option =>
            {
                option.UseMySql(configuration["SqlConnection:MySql"], new MySqlServerVersion(new Version(8, 0, 18)),
                    mySqlOptions => mySqlOptions.CharSetBehavior(CharSetBehavior.NeverAppend));
                //.EnableSensitiveDataLogging()
                //.EnableDetailedErrors(); 
            }, 128);

            return services;
        }
    }
}
